package com.gitee.wsl.time.chinese


import com.gitee.wsl.ext.string.EMPTY
import kotlinx.datetime.LocalDate


/**
 * 作者：Sun_LeiLei
 * 来源：CSDN
 * 原文：https://blog.csdn.net/sun_leilei/article/details/50148297
 * 版权声明：本文为博主原创文章，转载请附上博文链接！
 * Created by necer on 2018/11/16.
 */
object SolarTerm{
    private val D = 0.2422
    private val INCREASE_OFFSETMAP: MutableMap<String, Array<Int>> = HashMap() // +1偏移
    private val DECREASE_OFFSETMAP: MutableMap<String, Array<Int>> = HashMap() // -1偏移

    init {
        DECREASE_OFFSETMAP[SolarTermsEnum.YUSHUI.name] = arrayOf(2026) // 雨水
        INCREASE_OFFSETMAP[SolarTermsEnum.CHUNFEN.name] = arrayOf(2084) // 春分
        INCREASE_OFFSETMAP[SolarTermsEnum.XIAOMAN.name] = arrayOf(2008) // 小满
        INCREASE_OFFSETMAP[SolarTermsEnum.MANGZHONG.name] = arrayOf(1902) // 芒种
        INCREASE_OFFSETMAP[SolarTermsEnum.XIAZHI.name] = arrayOf(1928) // 夏至
        INCREASE_OFFSETMAP[SolarTermsEnum.XIAOSHU.name] = arrayOf(1925, 2016) // 小暑
        INCREASE_OFFSETMAP[SolarTermsEnum.DASHU.name] = arrayOf(1922) // 大暑
        INCREASE_OFFSETMAP[SolarTermsEnum.LIQIU.name] = arrayOf(2002) // 立秋
        INCREASE_OFFSETMAP[SolarTermsEnum.BAILU.name] = arrayOf(1927) // 白露
        INCREASE_OFFSETMAP[SolarTermsEnum.QIUFEN.name] = arrayOf(1942) // 秋分
        INCREASE_OFFSETMAP[SolarTermsEnum.SHUANGJIANG.name] = arrayOf(2089) // 霜降
        INCREASE_OFFSETMAP[SolarTermsEnum.LIDONG.name] = arrayOf(2089) // 立冬
        INCREASE_OFFSETMAP[SolarTermsEnum.XIAOXUE.name] = arrayOf(1978) // 小雪
        INCREASE_OFFSETMAP[SolarTermsEnum.DAXUE.name] = arrayOf(1954) // 大雪
        DECREASE_OFFSETMAP[SolarTermsEnum.DONGZHI.name] = arrayOf(1918, 2021) // 冬至
        INCREASE_OFFSETMAP[SolarTermsEnum.XIAOHAN.name] = arrayOf(1982) // 小寒
        DECREASE_OFFSETMAP[SolarTermsEnum.XIAOHAN.name] = arrayOf(2019) // 小寒
        INCREASE_OFFSETMAP[SolarTermsEnum.DAHAN.name] = arrayOf(2082) // 大寒
    }

    // 定义一个二维数组，第一维数组存储的是20世纪的节气C值，第二维数组存储的是21世纪的节气C值,0到23个，依次代表立春、雨水...大寒节气的C值
    private val CENTURY_ARRAY = arrayOf(
        doubleArrayOf(
            4.6295, 19.4599, 6.3826, 21.4155, 5.59, 20.888, 6.318, 21.86,
            6.5, 22.2, 7.928, 23.65, 8.35, 23.95, 8.44, 23.822, 9.098,
            24.218, 8.218, 23.08, 7.9, 22.6, 6.11, 20.84
        ),
        doubleArrayOf(
            3.87, 18.73, 5.63, 20.646, 4.81, 20.1, 5.52, 21.04, 5.678, 21.37,
            7.108, 22.83, 7.5, 23.13, 7.646, 23.042, 8.318, 23.438,
            7.438, 22.36, 7.18, 21.94, 5.4055, 20.12
        )
    )

    fun getSolarTermNum(year: Int, termsEnum: SolarTermsEnum): Int {
        var centuryValue = 0.0 // 节气的世纪值，每个节气的每个世纪值都不同
        val ordinal = termsEnum.ordinal
        var centuryIndex = -1
        if (year in 1901..2000) { // 20世纪
            centuryIndex = 0
        } else if (year in 2001..2100) { // 21世纪
            centuryIndex = 1
        } else {
            throw RuntimeException("不支持此年份：$year，目前只支持1901年到2100年的时间范围")
        }
        centuryValue = CENTURY_ARRAY[centuryIndex][ordinal]
        var dateNum = 0

        /**
         * 计算 num =[Y*D+C]-L这是传说中的寿星通用公式
         * 公式解读：年数的后2位乘0.2422加C(即：centuryValue)取整数后，减闰年数
         */
        var y = year % 100 // 步骤1:取年分的后两位数
        if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) { // 闰年
            if ((ordinal == SolarTermsEnum.XIAOHAN.ordinal) || (ordinal == SolarTermsEnum.DAHAN.ordinal) ||
                (ordinal == SolarTermsEnum.LICHUN.ordinal) || (ordinal == SolarTermsEnum.YUSHUI.ordinal)
            ) {
                // 注意：凡闰年3月1日前闰年数要减一，即：L=[(Y-1)/4],因为小寒、大寒、立春、雨水这两个节气都小于3月1日,所以
                // y = y-1
                y = y - 1 // 步骤2
            }
        }
        dateNum = (y * D + centuryValue).toInt() - (y / 4) // 步骤3，使用公式[Y*D+C]-L计算
        dateNum += specialYearOffset(year, termsEnum.name) // 步骤4，加上特殊的年分的节气偏移量
        return dateNum
    }

    /**
     * @param year 年份
     * @param name 节气的名称
     * @return 返回节气是相应月份的第几天
     */
    fun getSolarTermNum(year: Int, name: String): Int {
        return getSolarTermNum(year, SolarTermsEnum.valueOf(name.trim { it <= ' ' }.uppercase()))
    }

    /**
     * 特例,特殊的年分的节气偏移量,由于公式并不完善，所以算出的个别节气的第几天数并不准确，在此返回其偏移量
     *
     * @param year 年份
     * @param name 节气名称
     * @return 返回其偏移量
     */
    private fun specialYearOffset(year: Int, name: String): Int {
        var offset = 0
        offset += getOffset(DECREASE_OFFSETMAP, year, name, -1)
        offset += getOffset(INCREASE_OFFSETMAP, year, name, 1)
        return offset
    }

    private fun getOffset(
        map: Map<String, Array<Int>>, year: Int,
        name: String, offset: Int,
    ): Int {
        var off = 0
        val years = map[name]
        if (null != years) {
            for (i: Int in years) {
                if (i == year) {
                    off = offset
                    break
                }
            }
        }
        return off
    }

    private var mYear = 0
    private var mSolarData: MutableList<String>? = ArrayList()
    private var mSolarName: MutableList<String>? = ArrayList()

    /**
     * 判断一天是什么节气  公历日期
     *
     * @param year
     * @param data 月份占两位，日不确定，如一月一日为：011，五月十日为0510
     * @return
     * @data2015-12-2下午2:49:32
     */
    fun getSolatName(year: Int, data: String): String? {
        if (year != mYear) {
            solarTermToString(year)
        }
        return if (mSolarData!!.contains(data)) {
            mSolarName!!.get(mSolarData!!.indexOf(data))
        } else {
            null
        }
    }

    private fun solarTermToString(year: Int) {
        mYear = year
        if (mSolarData != null) {
            mSolarData!!.clear()
        } else {
            mSolarData = ArrayList()
        }
        if (mSolarName != null) {
            mSolarName!!.clear()
        } else {
            mSolarName = ArrayList()
        }
        // 1
        mSolarName!!.add("立春")
        mSolarData!!.add("02" + getSolarTermNum(year, SolarTermsEnum.LICHUN.name))
        // 2
        mSolarName!!.add("雨水")
        mSolarData!!.add("02" + getSolarTermNum(year, SolarTermsEnum.YUSHUI.name))
        // 3
        mSolarName!!.add("惊蛰")
        mSolarData!!.add("03" + getSolarTermNum(year, SolarTermsEnum.JINGZHE.name))
        // 4
        mSolarName!!.add("春分")
        mSolarData!!.add("03" + getSolarTermNum(year, SolarTermsEnum.CHUNFEN.name))
        // 5
        mSolarName!!.add("清明")
        mSolarData!!.add("04" + getSolarTermNum(year, SolarTermsEnum.QINGMING.name))
        // 6
        mSolarName!!.add("谷雨")
        mSolarData!!.add("04" + getSolarTermNum(year, SolarTermsEnum.GUYU.name))
        // 7
        mSolarName!!.add("立夏")
        mSolarData!!.add("05" + getSolarTermNum(year, SolarTermsEnum.LIXIA.name))
        // 8
        mSolarName!!.add("小满")
        mSolarData!!.add("05" + getSolarTermNum(year, SolarTermsEnum.XIAOMAN.name))
        // 9
        mSolarName!!.add("芒种")
        mSolarData!!.add("06" + getSolarTermNum(year, SolarTermsEnum.MANGZHONG.name))
        // 10
        mSolarName!!.add("夏至")
        mSolarData!!.add("06" + getSolarTermNum(year, SolarTermsEnum.XIAZHI.name))
        // 11
        mSolarName!!.add("小暑")
        mSolarData!!.add("07" + getSolarTermNum(year, SolarTermsEnum.XIAOSHU.name))
        // 12
        mSolarName!!.add("大暑")
        mSolarData!!.add("07" + getSolarTermNum(year, SolarTermsEnum.DASHU.name))
        // 13
        mSolarName!!.add("立秋")
        mSolarData!!.add("08" + getSolarTermNum(year, SolarTermsEnum.LIQIU.name))
        // 14
        mSolarName!!.add("处暑")
        mSolarData!!.add("08" + getSolarTermNum(year, SolarTermsEnum.CHUSHU.name))
        // 15
        mSolarName!!.add("白露")
        mSolarData!!.add("09" + getSolarTermNum(year, SolarTermsEnum.BAILU.name))
        // 16
        mSolarName!!.add("秋分")
        mSolarData!!.add("09" + getSolarTermNum(year, SolarTermsEnum.QIUFEN.name))
        // 17
        mSolarName!!.add("寒露")
        mSolarData!!.add("10" + getSolarTermNum(year, SolarTermsEnum.HANLU.name))
        // 18
        mSolarName!!.add("霜降")
        mSolarData!!.add("10" + getSolarTermNum(year, SolarTermsEnum.SHUANGJIANG.name))
        // 19
        mSolarName!!.add("立冬")
        mSolarData!!.add("11" + getSolarTermNum(year, SolarTermsEnum.LIDONG.name))
        // 20
        mSolarName!!.add("小雪")
        mSolarData!!.add("11" + getSolarTermNum(year, SolarTermsEnum.XIAOXUE.name))
        // 21
        mSolarName!!.add("大雪")
        mSolarData!!.add("12" + getSolarTermNum(year, SolarTermsEnum.DAXUE.name))
        // 22
        mSolarName!!.add("冬至")
        mSolarData!!.add("12" + getSolarTermNum(year, SolarTermsEnum.DONGZHI.name))
        // 23
        mSolarName!!.add("小寒")
        mSolarData!!.add("01" + getSolarTermNum(year, SolarTermsEnum.XIAOHAN.name))
        // 24
        mSolarName!!.add("大寒")
        mSolarData!!.add("01" + getSolarTermNum(year, SolarTermsEnum.DAHAN.name))
    }

    /**
     * 24节气
     */
    enum class SolarTermsEnum {
        LICHUN,// --立春
        YUSHUI,// --雨水
        JINGZHE,// --惊蛰
        CHUNFEN,// 春分
        QINGMING,// 清明
        GUYU,// 谷雨
        LIXIA,// 立夏
        XIAOMAN,// 小满
        MANGZHONG,// 芒种
        XIAZHI,// 夏至
        XIAOSHU,// 小暑
        DASHU,// 大暑
        LIQIU,// 立秋
        CHUSHU,// 处暑
        BAILU,// 白露
        QIUFEN,// 秋分
        HANLU,// 寒露
        SHUANGJIANG,// 霜降
        LIDONG,// 立冬
        XIAOXUE,// 小雪
        DAXUE, // 大雪
        DONGZHI,// 冬至
        XIAOHAN,// 小寒
        DAHAN // 大寒
    }

    /**
     * 1900-2100各年的24节气日期速查表
     * 此表来自：https://github.com/jjonline/calendar.js/blob/master/calendar.js
     */
    private  val S_TERM_INFO = arrayOf<String>(
        "9778397bd097c36b0b6fc9274c91aa", "97b6b97bd19801ec9210c965cc920e", "97bcf97c3598082c95f8c965cc920f",
        "97bd0b06bdb0722c965ce1cfcc920f", "b027097bd097c36b0b6fc9274c91aa", "97b6b97bd19801ec9210c965cc920e",
        "97bcf97c359801ec95f8c965cc920f", "97bd0b06bdb0722c965ce1cfcc920f", "b027097bd097c36b0b6fc9274c91aa",
        "97b6b97bd19801ec9210c965cc920e", "97bcf97c359801ec95f8c965cc920f", "97bd0b06bdb0722c965ce1cfcc920f",
        "b027097bd097c36b0b6fc9274c91aa", "9778397bd19801ec9210c965cc920e", "97b6b97bd19801ec95f8c965cc920f",
        "97bd09801d98082c95f8e1cfcc920f", "97bd097bd097c36b0b6fc9210c8dc2", "9778397bd197c36c9210c9274c91aa",
        "97b6b97bd19801ec95f8c965cc920e", "97bd09801d98082c95f8e1cfcc920f", "97bd097bd097c36b0b6fc9210c8dc2",
        "9778397bd097c36c9210c9274c91aa", "97b6b97bd19801ec95f8c965cc920e", "97bcf97c3598082c95f8e1cfcc920f",
        "97bd097bd097c36b0b6fc9210c8dc2", "9778397bd097c36c9210c9274c91aa", "97b6b97bd19801ec9210c965cc920e",
        "97bcf97c3598082c95f8c965cc920f", "97bd097bd097c35b0b6fc920fb0722", "9778397bd097c36b0b6fc9274c91aa",
        "97b6b97bd19801ec9210c965cc920e", "97bcf97c3598082c95f8c965cc920f", "97bd097bd097c35b0b6fc920fb0722",
        "9778397bd097c36b0b6fc9274c91aa", "97b6b97bd19801ec9210c965cc920e", "97bcf97c359801ec95f8c965cc920f",
        "97bd097bd097c35b0b6fc920fb0722", "9778397bd097c36b0b6fc9274c91aa", "97b6b97bd19801ec9210c965cc920e",
        "97bcf97c359801ec95f8c965cc920f", "97bd097bd097c35b0b6fc920fb0722", "9778397bd097c36b0b6fc9274c91aa",
        "97b6b97bd19801ec9210c965cc920e", "97bcf97c359801ec95f8c965cc920f", "97bd097bd07f595b0b6fc920fb0722",
        "9778397bd097c36b0b6fc9210c8dc2", "9778397bd19801ec9210c9274c920e", "97b6b97bd19801ec95f8c965cc920f",
        "97bd07f5307f595b0b0bc920fb0722", "7f0e397bd097c36b0b6fc9210c8dc2", "9778397bd097c36c9210c9274c920e",
        "97b6b97bd19801ec95f8c965cc920f", "97bd07f5307f595b0b0bc920fb0722", "7f0e397bd097c36b0b6fc9210c8dc2",
        "9778397bd097c36c9210c9274c91aa", "97b6b97bd19801ec9210c965cc920e", "97bd07f1487f595b0b0bc920fb0722",
        "7f0e397bd097c36b0b6fc9210c8dc2", "9778397bd097c36b0b6fc9274c91aa", "97b6b97bd19801ec9210c965cc920e",
        "97bcf7f1487f595b0b0bb0b6fb0722", "7f0e397bd097c35b0b6fc920fb0722", "9778397bd097c36b0b6fc9274c91aa",
        "97b6b97bd19801ec9210c965cc920e", "97bcf7f1487f595b0b0bb0b6fb0722", "7f0e397bd097c35b0b6fc920fb0722",
        "9778397bd097c36b0b6fc9274c91aa", "97b6b97bd19801ec9210c965cc920e", "97bcf7f1487f531b0b0bb0b6fb0722",
        "7f0e397bd097c35b0b6fc920fb0722", "9778397bd097c36b0b6fc9274c91aa", "97b6b97bd19801ec9210c965cc920e",
        "97bcf7f1487f531b0b0bb0b6fb0722", "7f0e397bd07f595b0b6fc920fb0722", "9778397bd097c36b0b6fc9274c91aa",
        "97b6b97bd19801ec9210c9274c920e", "97bcf7f0e47f531b0b0bb0b6fb0722", "7f0e397bd07f595b0b0bc920fb0722",
        "9778397bd097c36b0b6fc9210c91aa", "97b6b97bd197c36c9210c9274c920e", "97bcf7f0e47f531b0b0bb0b6fb0722",
        "7f0e397bd07f595b0b0bc920fb0722", "9778397bd097c36b0b6fc9210c8dc2", "9778397bd097c36c9210c9274c920e",
        "97b6b7f0e47f531b0723b0b6fb0722", "7f0e37f5307f595b0b0bc920fb0722", "7f0e397bd097c36b0b6fc9210c8dc2",
        "9778397bd097c36b0b70c9274c91aa", "97b6b7f0e47f531b0723b0b6fb0721", "7f0e37f1487f595b0b0bb0b6fb0722",
        "7f0e397bd097c35b0b6fc9210c8dc2", "9778397bd097c36b0b6fc9274c91aa", "97b6b7f0e47f531b0723b0b6fb0721",
        "7f0e27f1487f595b0b0bb0b6fb0722", "7f0e397bd097c35b0b6fc920fb0722", "9778397bd097c36b0b6fc9274c91aa",
        "97b6b7f0e47f531b0723b0b6fb0721", "7f0e27f1487f531b0b0bb0b6fb0722", "7f0e397bd097c35b0b6fc920fb0722",
        "9778397bd097c36b0b6fc9274c91aa", "97b6b7f0e47f531b0723b0b6fb0721", "7f0e27f1487f531b0b0bb0b6fb0722",
        "7f0e397bd097c35b0b6fc920fb0722", "9778397bd097c36b0b6fc9274c91aa", "97b6b7f0e47f531b0723b0b6fb0721",
        "7f0e27f1487f531b0b0bb0b6fb0722", "7f0e397bd07f595b0b0bc920fb0722", "9778397bd097c36b0b6fc9274c91aa",
        "97b6b7f0e47f531b0723b0787b0721", "7f0e27f0e47f531b0b0bb0b6fb0722", "7f0e397bd07f595b0b0bc920fb0722",
        "9778397bd097c36b0b6fc9210c91aa", "97b6b7f0e47f149b0723b0787b0721", "7f0e27f0e47f531b0723b0b6fb0722",
        "7f0e397bd07f595b0b0bc920fb0722", "9778397bd097c36b0b6fc9210c8dc2", "977837f0e37f149b0723b0787b0721",
        "7f07e7f0e47f531b0723b0b6fb0722", "7f0e37f5307f595b0b0bc920fb0722", "7f0e397bd097c35b0b6fc9210c8dc2",
        "977837f0e37f14998082b0787b0721", "7f07e7f0e47f531b0723b0b6fb0721", "7f0e37f1487f595b0b0bb0b6fb0722",
        "7f0e397bd097c35b0b6fc9210c8dc2", "977837f0e37f14998082b0787b06bd", "7f07e7f0e47f531b0723b0b6fb0721",
        "7f0e27f1487f531b0b0bb0b6fb0722", "7f0e397bd097c35b0b6fc920fb0722", "977837f0e37f14998082b0787b06bd",
        "7f07e7f0e47f531b0723b0b6fb0721", "7f0e27f1487f531b0b0bb0b6fb0722", "7f0e397bd097c35b0b6fc920fb0722",
        "977837f0e37f14998082b0787b06bd", "7f07e7f0e47f531b0723b0b6fb0721", "7f0e27f1487f531b0b0bb0b6fb0722",
        "7f0e397bd07f595b0b0bc920fb0722", "977837f0e37f14998082b0787b06bd", "7f07e7f0e47f531b0723b0b6fb0721",
        "7f0e27f1487f531b0b0bb0b6fb0722", "7f0e397bd07f595b0b0bc920fb0722", "977837f0e37f14998082b0787b06bd",
        "7f07e7f0e47f149b0723b0787b0721", "7f0e27f0e47f531b0b0bb0b6fb0722", "7f0e397bd07f595b0b0bc920fb0722",
        "977837f0e37f14998082b0723b06bd", "7f07e7f0e37f149b0723b0787b0721", "7f0e27f0e47f531b0723b0b6fb0722",
        "7f0e397bd07f595b0b0bc920fb0722", "977837f0e37f14898082b0723b02d5", "7ec967f0e37f14998082b0787b0721",
        "7f07e7f0e47f531b0723b0b6fb0722", "7f0e37f1487f595b0b0bb0b6fb0722", "7f0e37f0e37f14898082b0723b02d5",
        "7ec967f0e37f14998082b0787b0721", "7f07e7f0e47f531b0723b0b6fb0722", "7f0e37f1487f531b0b0bb0b6fb0722",
        "7f0e37f0e37f14898082b0723b02d5", "7ec967f0e37f14998082b0787b06bd", "7f07e7f0e47f531b0723b0b6fb0721",
        "7f0e37f1487f531b0b0bb0b6fb0722", "7f0e37f0e37f14898082b072297c35", "7ec967f0e37f14998082b0787b06bd",
        "7f07e7f0e47f531b0723b0b6fb0721", "7f0e27f1487f531b0b0bb0b6fb0722", "7f0e37f0e37f14898082b072297c35",
        "7ec967f0e37f14998082b0787b06bd", "7f07e7f0e47f531b0723b0b6fb0721", "7f0e27f1487f531b0b0bb0b6fb0722",
        "7f0e37f0e366aa89801eb072297c35", "7ec967f0e37f14998082b0787b06bd", "7f07e7f0e47f149b0723b0787b0721",
        "7f0e27f1487f531b0b0bb0b6fb0722", "7f0e37f0e366aa89801eb072297c35", "7ec967f0e37f14998082b0723b06bd",
        "7f07e7f0e47f149b0723b0787b0721", "7f0e27f0e47f531b0723b0b6fb0722", "7f0e37f0e366aa89801eb072297c35",
        "7ec967f0e37f14998082b0723b06bd", "7f07e7f0e37f14998083b0787b0721", "7f0e27f0e47f531b0723b0b6fb0722",
        "7f0e37f0e366aa89801eb072297c35", "7ec967f0e37f14898082b0723b02d5", "7f07e7f0e37f14998082b0787b0721",
        "7f07e7f0e47f531b0723b0b6fb0722", "7f0e36665b66aa89801e9808297c35", "665f67f0e37f14898082b0723b02d5",
        "7ec967f0e37f14998082b0787b0721", "7f07e7f0e47f531b0723b0b6fb0722", "7f0e36665b66a449801e9808297c35",
        "665f67f0e37f14898082b0723b02d5", "7ec967f0e37f14998082b0787b06bd", "7f07e7f0e47f531b0723b0b6fb0721",
        "7f0e36665b66a449801e9808297c35", "665f67f0e37f14898082b072297c35", "7ec967f0e37f14998082b0787b06bd",
        "7f07e7f0e47f531b0723b0b6fb0721", "7f0e26665b66a449801e9808297c35", "665f67f0e37f1489801eb072297c35",
        "7ec967f0e37f14998082b0787b06bd", "7f07e7f0e47f531b0723b0b6fb0721", "7f0e27f1487f531b0b0bb0b6fb0722"
    )

    /**
     * 24节气
     */
    private val TERMS = arrayOf<String>(
        "小寒", "大寒", "立春", "雨水", "惊蛰", "春分",
        "清明", "谷雨", "立夏", "小满", "芒种", "夏至",
        "小暑", "大暑", "立秋", "处暑", "白露", "秋分",
        "寒露", "霜降", "立冬", "小雪", "大雪", "冬至"
    )

    /**
     * 传入公历y年获得该年第n个节气的公历日期
     *
     * @param y  公历年(1900-2100)
     * @param n 二十四节气中的第几个节气(1~24)；从n=1(小寒)算起
     * @return getTerm(1987,3) -》4;意即1987年2月4日立春
     */
    fun getTerm(y: Int, n: Int): Int {
        if (y < 1900 || y > 2100) {
            return -1
        }
        if (n < 1 || n > 24) {
            return -1
        }

        val _table = S_TERM_INFO[y - 1900]
        val _info = kotlin.arrayOfNulls<Int>(6)
        for (i in 0..5) {
            _info[i] = _table.substring(i * 5, 5 * (i + 1)).toInt(16)
        }
        val _calday = kotlin.arrayOfNulls<String>(24)
        for (i in 0..5) {
            _calday[4 * i] = _info[i].toString().substring(0, 1)
            _calday[4 * i + 1] = _info[i].toString().substring(1, 3)
            _calday[4 * i + 2] = _info[i].toString().substring(3, 4)
            _calday[4 * i + 3] = _info[i].toString().substring(4, 6)
        }
        return _calday[n - 1]!!.toInt()
    }

    /**
     * 根据日期获取节气
     * @param date 日期
     * @return 返回指定日期所处的节气，若不是一个节气则返回空字符串
     */
    fun getTerm(date: LocalDate): String? {
        return getTermInternal(date.year, date.monthNumber, date.dayOfMonth)
    }


    /**
     * 根据农历日期获取节气
     * @param chineseDate 农历日期
     * @return 返回指定农历日期所处的节气，若不是一个节气则返回空字符串
     */
    fun getTerm(chineseDate: ChineseDate): String {
        return chineseDate.term
    }


    /**
     * 根据年月日获取节气
     * @param year 公历年
     * @param mouth 公历月，从1开始
     * @param day 公历日，从1开始
     * @return 返回指定年月日所处的节气，若不是一个节气则返回空字符串
     */
    fun getTerm(year: Int, mouth: Int, day: Int): String? {
        return getTermInternal(year, mouth, day)
    }

    /**
     * 根据年月日获取节气, 内部方法，不对月和日做有效校验
     * @param year 公历年
     * @param mouth 公历月，从1开始
     * @param day 公历日，从1开始
     * @return 返回指定年月日所处的节气，若不是一个节气则返回空字符串
     */
    private fun getTermInternal(year: Int, mouth: Int, day: Int): String? {
        require(!(year < 1900 || year > 2100)) { "只支持1900-2100之间的日期获取节气" }

        val termTable = S_TERM_INFO[year - 1900]

        // 节气速查表中每5个字符含有4个节气，通过月份直接计算偏移
        val segment = (mouth + 1) / 2 - 1
        val termInfo = termTable.substring(segment * 5, (segment + 1) * 5).toInt(16)
        val termInfoStr = termInfo.toString()

        val segmentTable = kotlin.arrayOfNulls<String>(4)
        segmentTable[0] = termInfoStr.substring(0, 1)
        segmentTable[1] = termInfoStr.substring(1, 3)
        segmentTable[2] = termInfoStr.substring(3, 4)
        segmentTable[3] = termInfoStr.substring(4, 6)

        // 奇数月份的节气在前2个，偶数月份的节气在后两个
        val segmentOffset = if ((mouth and 1) == 1) 0 else 2

        if (day == segmentTable[segmentOffset]!!.toInt()) {
            return TERMS[segment * 4 + segmentOffset]
        }
        if (day == segmentTable[segmentOffset + 1]!!.toInt()) {
            return TERMS[segment * 4 + segmentOffset + 1]
        }
        return String.EMPTY
    }
}